#include "vtor_iap.h"
#include "vtor_timer.h"
#include "vtor_printf.h"
#include "vtor_flash_eeprom.h"
#include "main.h"

#ifdef __VTOR_IAP_BOOT__

// 外部声明变量，覆盖写flash的buffer，记录版本信息等
extern uint8_t iapFlashBuf[VtorIapBufSize + 10];
extern VtorFlashEeprom vtorIapEeprom;
extern VtorIapEepromData iapEepromData;

// 函数指针，用于跳转到app
typedef void (*JumpAppFun)(void);


//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(volatile uint32_t addr) 
{
    MSR MSP, r0 			//set Main Stack value
    BX r14
}

int VtorIap_Update()
{
	
	for(int i = 0; i < APK_PAGE_CNT; i++)
	{
		uint32_t srcAddr = i * VtorFlashPageSize + BAK_ADDR;
		uint32_t dstAddr = i * VtorFlashPageSize + APP_ADDR;
		
		VtorFlash_Erase(dstAddr, 1);
		VtorFlash_Read(srcAddr, (uint32_t*)iapFlashBuf, VtorFlashPageSize);
		VtorFlash_Write(dstAddr, (uint32_t*)iapFlashBuf, VtorFlashPageSize);
	}
	
	return 0;
}


void VtorIap_CheckUpdate()
{
	//VtorFlashEeprom_Erase(&vtorIapEeprom);
	VtorFlashEeprom_Read(&vtorIapEeprom, &iapEepromData, sizeof(iapEepromData));
	if(iapEepromData.newFile.fileVersion > iapEepromData.curFile.fileVersion)
	{
		VtorDebugChanPrintf("iap : app will upgrade %d -> %d \r\n",
			iapEepromData.curFile.fileVersion, iapEepromData.newFile.fileVersion);
		// 执行更新操作，如果更新成功，才写入更新后的版本
		
		if(0 == VtorIap_Update())
		{
			// 更新文件名，更新文件大小，更新版本，更新crc
			int32_t nameLen = VTOR_IAP_FILE_NAME_LEN;
			VtorString_AppendString(iapEepromData.curFile.fileName,
				&nameLen,iapEepromData.newFile.fileName);
			iapEepromData.curFile.fileSize = iapEepromData.newFile.fileSize;
			iapEepromData.curFile.fileVersion = iapEepromData.newFile.fileVersion;
			iapEepromData.curFile.fileCrc = iapEepromData.newFile.fileCrc;
			VtorFlashEeprom_Write(&vtorIapEeprom, &iapEepromData, sizeof(iapEepromData));
			VtorDebugChanPrintf("iap : upgrade success\r\n");
		}
	}
}

//跳转到应用程序段
//appxaddr:用户代码起始地址.
void VtorIap_JumpApp(uint32_t appxaddr)
{
	// https://blog.csdn.net/ZZZganfan/article/details/134367775

    //定义函数指针
	JumpAppFun jumpAppFun;
	if(((*(volatile uint32_t*)appxaddr)&0x2FFE0000)==0x20000000)      //检查栈顶地址是否合法.
	{
		jumpAppFun=(JumpAppFun)*(volatile uint32_t*)(appxaddr+4);         
		//用户代码区第二个字为程序开始地址(复位地址)         
		//__set_MSP(*(volatile uint32_t*)APP_ADDR);
		MSR_MSP(*(volatile uint32_t*)appxaddr);

        for(int i = 0; i < 8; i++) {
            NVIC->ICER[i] = 0xFFFFFFFF; // 关闭中断
            NVIC->ICPR[i] = 0xFFFFFFFF; // 清除中断标志位
        }
        // DeInit();
        SysTick->CTRL = 0;
        SysTick->LOAD = 0;
        SysTick->VAL = 0;

		//跳转到APP
		//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		SCB->VTOR = APP_ADDR;
		
		jumpAppFun();    //跳转到APP.
	}
}


#endif // __VTOR_IAP_BOOT__

